#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
char buf[500000];

void set_fl(int fd, int flags) /* flags are file status flags to turn on */
{
    int        val;

    if ( (val = fcntl(fd, F_GETFL, 0)) < 0)
    {
        exit(1);
    }

    val |= flags;        /* turn on flags */

    if (fcntl(fd, F_SETFL, val) < 0)
    {
        exit(1);
    }
}
void clr_fl(int fd, int flags)
{
    int val;

    if ((val = fcntl(fd, F_GETFL, 0)) == -1)
    {
        exit(1);
    }
    val &= ~flags; /* turn flags off */

    if (fcntl(fd, F_SETFL, val) == -1)
    {
        exit(1);
    }
    return;
}

int main(void){
    int ntowirte, nwirte;
    char *ptr;

    ntowirte = read(STDIN_FILENO, buf, sizeof(buf));
    fprintf(stderr, "read %d bytes\n", ntowirte);

    set_fl(STDOUT_FILENO, O_NONBLOCK);

    ptr = buf;
    while(ntowirte > 0){
        errno = 0;
        nwirte = write(STDOUT_FILENO, ptr, ntowirte);
        fprintf(stderr, "nwrite = %d, errno = %d\n", nwirte, errno);

        if(nwirte > 0){
            ptr += nwirte;
            ntowirte -= nwirte;
        }
    }

    clr_fl(STDOUT_FILENO, O_NONBLOCK);

    exit(0);
}

/*
    如果标准输出是普通文件，则可以期望wirte只执行一次。
    但是，如果标准输出是终端，则期望write有时返回小于500000的一个数，有时返回错误。在此情况下，循环中可能只有部分返回成功，剩下的请求全部
    返回错误。这种形式称为轮询，在多用户系统上用它会浪费cpu时间。可以使用非阻塞描述符的I/O多路转接，这是进行这种操作的一种比较有效的方法。
*/